package com.example.statemachine;

import com.example.controller.EventResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.access.StateMachineAccess;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.support.DefaultStateMachineContext;
import org.springframework.stereotype.Component;

@Component("incomeRegistrationStateMachine")
@Slf4j
@RequiredArgsConstructor
public class ApplicationStateMachine {

    private final StateMachineFactory<StatesEvents.State, StatesEvents.Event> stateMachineFactory;

    public EventResponse sentEvent(StatesEvents.State state, String event, ApplicationRequest applicationRequest) {

        log.info("StateMachine state {} ", state);
        log.info("StateMachine sendEvent {} ", event);
        log.info("StateMachine applicationId {} ", applicationRequest.getApplicationId());
        StateMachine<StatesEvents.State, StatesEvents.Event> stateMachine = stateMachineFactory.getStateMachine(applicationRequest.getApplicationId());
        stateMachine.stop();
        stateMachine.getStateMachineAccessor().doWithAllRegions(access -> resetMachine(access, state));
        stateMachine.start();
        stateMachine.sendEvent(MessageBuilder.withPayload(StatesEvents.Event.fromValue(event))
                .setHeader("UPDATE_REQUEST", applicationRequest)
                .build());
        if (stateMachine.hasStateMachineError()) {
            return EventResponse.builder()
                    .message("Fail")
                    .build();
        }
        return EventResponse.builder()
                .targetState(stateMachine.getState().getId().toString())
                .message("success")
                .build();
    }


    private void resetMachine(StateMachineAccess<StatesEvents.State, StatesEvents.Event> access, StatesEvents.State state) {
        access.resetStateMachine(new DefaultStateMachineContext<StatesEvents.State, StatesEvents.Event>(state, null, null, null));
    }
}
